package com.ylr.config.framework.init;

import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-04-28 23:06:05
 * className: InitRunner
 * version: 1.0
 * description:
 */
@Component
@AllArgsConstructor
public class InitRunner implements CommandLineRunner {

    private static final Logger log = LoggerFactory.getLogger(InitRunner.class);

    private final RabbitTemplate rabbitTemplate;

    @Override
    public void run(String... args) {

        initRabbitMq();

    }

    /**
     * 初始化rabbitMq配置
     */
    private void initRabbitMq() {
        log.info("开始初始化系统中间件RabbitMQ业务");

        /*
            配置发送消息的回调方法，不管发送成功还是发送失败，都会回调
                回调方法参数说明：
                    1、correlationData：存储回调消息的id及消息相关信息
                    2、ack：            消息发送结果[true-成功 false-失败]
                    3、cause：          消息发送失败原因（发送成功，该值为空）
                几种回调情况：
                    1、发送消息，交换机收到了，回调（ack：true）
                    2、发送消息，交换机接收失败，回调（ack：false，cause：失败原因）
         */
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            log.debug("回调参数correlationData={}", correlationData);
            String id = null;
            if (correlationData != null) {
                id = correlationData.getId();
//                log.info("message={}", correlationData.getReturned());
            }
            if (ack) {
                // 发送成功
                log.debug("交换机已经收到id={}的消息", id);
            } else {
                // 发送失败
                log.error("交换机还未收到id={}的消息，失败原因：{}", id, cause);
            }
        });

        /*
            当消息由交换机发送到队列时，可能转发失败，则回调该函数，将消息返还给生产者
                可能导致失败的原因：
                    1、队列宕机
                    2、路由键无法对应的队列
                回调方法参数说明：
                    1、returned：封装转发失败返回结果的对象，可以获取相关参数（状态码、提示消息、交换机名称、路由键、发送的消息）
         */
        rabbitTemplate.setReturnsCallback(returned -> log.error("消息转发失败，由交换机返还给生产者。replyText={} replyCode={}", returned.getReplyText(), returned.getReplyCode()));

        log.info("初始化系统中间件RabbitMQ业务结束");
    }
}
